//
//  NDLocationManager.swift
//  NyamanDana
//
//  Created by 李永彬 on 2025/10/27.
//

import UIKit
import NetworkExtension
import CoreLocation
import SystemConfiguration.CaptiveNetwork

// MARK: - 数据模型
struct NDLocationInfo {
    let coordinate: CLLocationCoordinate2D
    let countryCode: String?
    let country: String?
    let province: String?
    let city: String?
    let district: String?
    let street: String?
    let formattedAddress: String?
    
    var latitude: Double { coordinate.latitude }
    var longitude: Double { coordinate.longitude }
}

struct NDWifiInfo {
    let ssid: String?
    let bssid: String?
    let signalStrength: Int?
}

// MARK: - 错误类型
enum NDLocationError: Error {
    case permissionDenied
    case locationUpdateFailed(Error)
    case geocodingFailed
    case wifiInfoUnavailable
    case permissionRestricted
}

// MARK: - 回调类型
typealias NDLocationPermissionCompletion = (Bool) -> Void
typealias NDLocationCompletion = (Result<NDLocationInfo, NDLocationError>) -> Void
typealias NDWifiCompletion = (NDWifiInfo?, NDLocationError?) -> Void

// MARK: - 主管理类
final class NDLocationManager: NSObject {
    
    // MARK: - 属性
    static let shared = NDLocationManager()
    
    private let locationManager: CLLocationManager
    private var locationCompletion: NDLocationCompletion?
    private var wifiCompletion: NDWifiCompletion?
    private var permissionCompletion: NDLocationPermissionCompletion?
    private var isLocationUpdateInProgress = false
    
    // MARK: - 初始化
    override init() {
        self.locationManager = CLLocationManager()
        super.init()
        
        setupLocationManager()
        setupNotifications()
    }
    
    deinit {
        removeNotifications()
    }
    
    // MARK: - 公开方法
    /// 请求定位权限
    func requestLocationPermission(completion: NDLocationPermissionCompletion? = nil) {
        let status = locationManager.authorizationStatus
        
        switch status {
        case .notDetermined:
            self.permissionCompletion = completion
            locationManager.requestWhenInUseAuthorization()
            
        case .authorizedWhenInUse, .authorizedAlways:
            completion?(true)
            
        case .denied, .restricted:
            showLocationPermissionAlert()
            completion?(false)
            
        @unknown default:
            completion?(false)
        }
    }
    
    /// 获取完整位置信息
    func getCurrentLocation(completion: @escaping NDLocationCompletion) {
        requestLocationPermission { [weak self] granted in
            guard let self = self else { return }
            
            if granted {
                self.startLocationUpdate(completion: completion)
            } else {
                completion(.failure(.permissionDenied))
            }
        }
    }
    
    /// 获取WiFi信息
    func getCurrentWifiInfo(completion: @escaping NDWifiCompletion) {
        // 检查定位权限（iOS 13+ 需要）
        if #available(iOS 13.0, *) {
            let status = locationManager.authorizationStatus
            guard status == .authorizedWhenInUse || status == .authorizedAlways else {
                return
            }
        }
        
        self.wifiCompletion = completion
        fetchWifiInfo()
    }
    
    /// 获取最后已知位置（如果有）
    func getLastKnownLocation() -> NDLocationInfo? {
        guard let latitude = NDUserDefaults.shared.retrieveFloat(for: NDCoordinateLatKey),
              let longitude = NDUserDefaults.shared.retrieveFloat(for: NDCoordinateLngKey),
              latitude != 0, longitude != 0 else {
            return nil
        }
        
        let coordinate = CLLocationCoordinate2D(latitude: CLLocationDegrees(latitude), longitude: CLLocationDegrees(longitude))
        return NDLocationInfo(
            coordinate: coordinate,
            countryCode: nil,
            country: nil,
            province: nil,
            city: nil,
            district: nil,
            street: nil,
            formattedAddress: nil
        )
    }
}

// MARK: - 私有方法
private extension NDLocationManager {
    
    func setupLocationManager() {
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = kCLDistanceFilterNone
    }
    
    func setupNotifications() {
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(appDidBecomeActive),
            name: UIApplication.didBecomeActiveNotification,
            object: nil
        )
    }
    
    func removeNotifications() {
        NotificationCenter.default.removeObserver(self)
    }
    
    @objc func appDidBecomeActive() {
        // 应用重新激活时检查权限状态
        requestLocationPermission()
    }
    
    func startLocationUpdate(completion: @escaping NDLocationCompletion) {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            
            self.locationCompletion = completion
            self.isLocationUpdateInProgress = true
            self.locationManager.startUpdatingLocation()
        }
    }
    
    func fetchWifiInfo() {
        if #available(iOS 14.0, *) {
            fetchWithNEHotspotNetwork()
        } else {
            fetchWithCNCopy()
        }
    }
    
    @available(iOS 14.0, *)
    func fetchWithNEHotspotNetwork() {
        NEHotspotNetwork.fetchCurrent { [weak self] network in
            if let network = network {
                let wifiInfo = NDWifiInfo(
                    ssid: network.ssid,
                    bssid: network.bssid,
                    signalStrength: nil
                )
                self?.wifiCompletion?(wifiInfo, nil)
                self?.wifiCompletion = nil
            } else {
                self?.fetchWithCNCopy()
            }
        }
    }
    
    func fetchWithCNCopy() {
        DispatchQueue.global(qos: .utility).async { [weak self] in
            var ssid: String?
            var bssid: String?
            
            if let interfaces = CNCopySupportedInterfaces() as? [String] {
                for interface in interfaces {
                    guard let info = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any] else {
                        continue
                    }
                    ssid = info[kCNNetworkInfoKeySSID as String] as? String
                    bssid = info[kCNNetworkInfoKeyBSSID as String] as? String
                    break
                }
            }
            
            DispatchQueue.main.async {
                if let ssid = ssid, let bssid = bssid {
                    let wifiInfo = NDWifiInfo(ssid: ssid, bssid: bssid, signalStrength: nil)
                    self?.wifiCompletion?(wifiInfo, nil)
                } else {
                    self?.wifiCompletion?(nil, .wifiInfoUnavailable)
                }
                self?.wifiCompletion = nil
            }
        }
    }
    
    func reverseGeocodeLocation(_ location: CLLocation, completion: @escaping NDLocationCompletion) {
        let geocoder = CLGeocoder()
        geocoder.reverseGeocodeLocation(location) { [weak self] placemarks, error in
            if let _ = error {
                completion(.failure(.geocodingFailed))
                return
            }
            
            guard let placemark = placemarks?.first else {
                completion(.failure(.geocodingFailed))
                return
            }
            
            let locationInfo = self?.createLocationInfo(from: placemark, location: location)
            if let locationInfo = locationInfo {
                completion(.success(locationInfo))
            } else {
                completion(.failure(.geocodingFailed))
            }
        }
    }
    
    func createLocationInfo(from placemark: CLPlacemark, location: CLLocation) -> NDLocationInfo {
        let coordinate = location.coordinate
        
        // 保存坐标到本地
        NDUserDefaults.shared.saveFloat(Float(coordinate.latitude), for: NDCoordinateLatKey)
        NDUserDefaults.shared.saveFloat(Float(coordinate.longitude), for: NDCoordinateLngKey)
        
        return NDLocationInfo(
            coordinate: coordinate,
            countryCode: placemark.isoCountryCode,
            country: placemark.country,
            province: placemark.administrativeArea,
            city: placemark.locality ?? placemark.administrativeArea,
            district: placemark.subLocality,
            street: placemark.thoroughfare,
            formattedAddress: formatAddress(from: placemark)
        )
    }
    
    func formatAddress(from placemark: CLPlacemark) -> String? {
        let components = [
            placemark.thoroughfare,
            placemark.subLocality,
            placemark.locality,
            placemark.administrativeArea,
            placemark.country
        ].compactMap { $0 }
        
        return components.isEmpty ? nil : components.joined(separator: ", ")
    }
    
    func showLocationPermissionAlert() {
        guard WJAppEnvironment.shared.currentCountry == .indonesia else {
            return
        }
        
        NotificationCenter.default.post(name: .showLocationAlertNotification, object: nil)
    }
}

// MARK: - CLLocationManagerDelegate
extension NDLocationManager: CLLocationManagerDelegate {
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .authorizedWhenInUse, .authorizedAlways:
            permissionCompletion?(true)
        case .denied, .restricted:
            permissionCompletion?(false)
        default:
            break
        }
        permissionCompletion = nil
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        
        if let location = locations.last {
            NDUserDefaults.shared.saveFloat(Float(location.coordinate.latitude), for: NDCoordinateLatKey)
            NDUserDefaults.shared.saveFloat(Float(location.coordinate.longitude), for: NDCoordinateLngKey)
        }
        
        guard let location = locations.last, isLocationUpdateInProgress else { return }
        
        manager.stopUpdatingLocation()
        isLocationUpdateInProgress = false
        
        reverseGeocodeLocation(location) { [weak self] result in
            self?.locationCompletion?(result)
            self?.locationCompletion = nil
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        if isLocationUpdateInProgress {
            isLocationUpdateInProgress = false
            locationCompletion?(.failure(.locationUpdateFailed(error)))
            locationCompletion = nil
        }
    }
}


